﻿using System;
using System.Text;
using System.IO;
using System.Linq;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections.Generic;

namespace Steganograf
{
    class BmpStegoFile
    {
				
		public BmpStegoFile(string pFileName) 
        {
			this.m_fileName = pFileName;
		}

        public BmpStegoFile(byte[] pBmpFile)
        {
            this.m_bmpFileBytes = pBmpFile;
        }

        public void SaveToFile(string pFileName)
        {
            if (m_bmpFileBytes != null)
            {
                try
                {
                    using (FileStream outStream = new FileStream(pFileName, FileMode.Create, FileAccess.Write))
                    {
                        outStream.Write(m_bmpFileBytes, 0, m_bmpFileBytes.Length);
                    }
                }
                catch
                {
                    throw new Exception("Zapis nie powiódł się. Wystąpił nieznany błąd.");
                }                
            }
        }

        public string GetHiddenMessage(string pPassword)
        {
            ExtractHiddenMessage(pPassword);
            return m_hiddenMessage;
        }

        protected void ExtractHiddenMessage(string pPassword) 
        {
			/* Open the bmp file */
            if(m_bmpFileBytes == null)
            {
                using (Stream inStream = new FileStream(m_fileName, FileMode.Open, FileAccess.Read))
                {
                    m_bmpFileBytes = new byte[inStream.Length];
                    inStream.Read(m_bmpFileBytes, 0, m_bmpFileBytes.Length);
                    inStream.Seek(0, 0);
                }
            }

            m_bmpBitmap = new Bitmap(ByteArray.ToImage(m_bmpFileBytes));
			
			/* Decode the 4 bytes containing the length of the message, using the LSB method */
            int offset = 54;
            byte[] bLen = LsbHelper.DecodeLength(m_bmpFileBytes, offset, 4);
			int len = BitConverter.ToInt32(bLen, 0);
            if (len == 0)
                throw new Exception("Brak ukrytej wiadomości");
            
			/* Decode the message using the LSB method */
            byte[] byteMessage = LsbHelper.Decode(m_bmpFileBytes, offset + 4 * 8, len, pPassword);									
			
			/* Get the hidden utf8 message */
            m_hiddenMessage = Crypto.DecryptAes(new UTF8Encoding().GetString(byteMessage), pPassword); 
		}

        public void CorrectHistogram(Dictionary<string, int> pPixels, Bitmap pOriginalFile)
        {
            foreach(string pixelsKey in pPixels.Keys)
            {
                int x = int.Parse(pixelsKey.Split('|')[0]);
                int y = int.Parse(pixelsKey.Split('|')[1]);
                if (x < 16) continue;
                if (pPixels[pixelsKey] > 0)
                {
                    Color c = pOriginalFile.GetPixel(x, y);
                    m_bmpBitmap.SetPixel(x, y, c);
                }
            }
        }

        private void ReadNewBmpToByteArrayAndFlip()
        {
            using (MemoryStream stream = new MemoryStream())
            {
                ImageCodecInfo bmpCodec = ImageCodecInfo.GetImageEncoders().Where(
                    codec => codec.FormatID.Equals(ImageFormat.Bmp.Guid)).FirstOrDefault();

                System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.ColorDepth;
                EncoderParameters parameters = new EncoderParameters();
                parameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.ColorDepth, 24);

                m_bmpBitmap.Save(stream, bmpCodec, parameters);
                m_bmpFileBytes = stream.ToArray();
            }

            m_bmpBitmap = new Bitmap(ByteArray.ToImage(m_bmpFileBytes));
        }

        public Bitmap Bitmap
        {
            get
            {
                if (m_bmpBitmap == null) 
                    m_bmpBitmap = new Bitmap(ByteArray.ToImage(m_bmpFileBytes));

                return m_bmpBitmap;
            }
        }

        private string m_fileName;
        private string m_hiddenMessage;
        private byte[] m_bmpFileBytes;
        private Bitmap m_bmpBitmap = null;
    }
}
